package com.example.number_convert;

import org.apache.poi.ss.usermodel.*;
import org.apache.poi.xssf.streaming.SXSSFWorkbook;
import org.apache.poi.xssf.usermodel.XSSFWorkbook;
import org.springframework.stereotype.Service;

import java.io.*;
import java.util.*;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

@Service
public class NumberService {
    private static List<Integer> NUMBER = new ArrayList<>();
    private static List<String> unit = Arrays.asList("十","百","千","万");

    public static void main(String[] args) {
        if (args.length == 1 && "-help".equals(args[0])){
            System.out.println("java -jar *.jar <srcPath> <targetPath>");
            System.out.println("参数srcPath ：源excel文件所在路径 （必须）");
            System.out.println("参数targetPath ：目标excel文件所在路径 （必须）");
            System.out.println("tip1.请准备足够的系统运行空间！");
            System.out.println("tip2.请使用jdk1.8+！");
            System.out.println("tip3.对于文本的替换是全局替换，极低概率造成替换错误！");
            System.out.println("tip4.针对单个字母的替换目前只有 U - 单位 做了匹配，其余字母可能发生替换错误！");
            System.out.println("tip4.目前只支持千万级以下的数进行口语化转换！");
            System.out.println("tip5.源excel中的内容必须放在第一个sheet。");
            return;
        }
        if (args.length < 2){
            System.out.println("缺少参数！【java -jar *.jar -help 查看帮助】");
            return;
        }

       if (!"xls".equals(args[0].substring(args[0].lastIndexOf(".") + 1)) && !"xlsx".equals(args[0].substring(args[0].lastIndexOf(".") + 1))){
           System.out.println("目前后缀只支持 .xls  .xlsx");
           return;
       };
        NumberService numberService = new NumberService();
        numberService.convertExcel(args[0],args[1]);
    }

    /**
     * 处理之前的判断
     * @param number
     * @return
     */
    public String numberFormat(Integer number) {
        NUMBER.clear();
        getNumber(number);
        if (NUMBER.size() >8){
            StringBuilder stringBuilder = new StringBuilder();
            Collections.reverse(NUMBER);
            for (Integer i : NUMBER) {
                stringBuilder.append(i.toString());
            }
            System.out.println("暂时无法处理内容，请先手动更改：" + stringBuilder);
            NUMBER.clear();
            return null;
        }
        if (NUMBER.size() == 1 && NUMBER.get(0) == 0) {
            //System.out.println("零");
            return "零";
        }
        //System.out.println(NUMBER);
        /*获取数字位数*/
        if (NUMBER.size() > 4){
            //大于四位
            //System.out.println("大于四位");
            //高位
            List<Integer> highF = NUMBER.subList(4, NUMBER.size());
            //低位
            List<Integer> lowF = NUMBER.subList(0, 4);

            String h = convertNumber(highF);
            String l = convertNumber(lowF);
            NUMBER.clear();
            //System.out.println( h + "万" + l);
            return h + "万" + l;
        }else {
            //小于四位;
            return convertNumber(NUMBER);

        }

    }

    /**
     * 转换四位数以内 并且开头一定不为0 【*核心方法*】
     */
    private static String convertNumber(List<Integer> nums) {
        List<String> numName = Arrays.asList("一","二","三","四","五","六","七","八","九","零");
        StringBuilder result = new StringBuilder();
        //两位数，十分位是1的特殊情况。
        if (nums.size() == 2 && nums.get(1) == 1) {
            result.append("十");
            if (nums.get(0) == 0){
                return result.toString();
            }
            result.append(numName.get(nums.get(0) - 1));
            return result.toString();
        }

        boolean bool = true;
        //[0, 3, 1, 2]
        for (int i = nums.size() - 1; i > 0; i--) {
            if (nums.get(i) == 0){
                if (bool){
                    bool = false;
                    //判断如果0在开头不添加
                    /*if (nums.get(nums.size() - 1) != 0){
                        result.append("零");
                    }*/
                    result.append("零");
                }
                continue;
            }
            bool = true;
            //获取读数 开头
            if (nums.get(i) == 2 && i == nums.size() - 1  && nums.size() != 2) {
                result.append("两");
            } else {
                result.append(numName.get(nums.get(i) - 1));
            }
            //获取单位
            String s = unit.get(i - 1);
            result.append(s);
        }
        //末尾
        if (nums.get(0) != 0) {
            result.append(numName.get(nums.get(0) - 1));
        }
        /*末尾以零结尾*/
        String s = result.toString();

        if ("零".equals(s.substring(s.length() - 1))){
            s = s.substring(0, s.length() - 1);
        }

        return s;
    }

    /**
     * 获取每一位数字
     * @param number
     */
    public static void getNumber(int number){
        int yushu = number % 10;
        NUMBER.add(yushu);
        int result = number / 10;
        if (result != 0 ){
            getNumber(result);
        }
    }


    /***
     * 读取excel文件 并写入Excel中
     * @param sourceExcelPath  【*主方法*】
     * @param targetExcelPath
     * @return
     */
    public void convertExcel(String sourceExcelPath, String targetExcelPath) {
        File srcFile = new File(sourceExcelPath);
        //
        Workbook workbook = null;
        //
        Workbook targetFos = new XSSFWorkbook();

        //输出流
        FileOutputStream fileOutputStream = null;
        try {
            workbook = WorkbookFactory.create(srcFile);
            Sheet sheet = workbook.getSheetAt(0); //默认只读第一个sheet

            int rowCount = sheet.getPhysicalNumberOfRows(); // 获取不为空的总行数
            System.out.println("总行数为：" + rowCount);
            //创建输出流
            Sheet writeSheet = targetFos.createSheet();

            int flag = 0;
            //开始写入
            for (int i = 0; i < rowCount ; i++) {
                if (i*100/rowCount != flag){
                    flag = i*100/rowCount;
                    System.out.println("当前进度：" + flag + "%");
                }
                Row row = sheet.getRow(i);
                if (row == null){
                    continue;
                }
                Cell cell = row.getCell(0);
                String value = cell.getStringCellValue();
                /*处理数据 【*】注意：转换顺序不可改变*/
                //region
                value = formatScienceCounting(value);
                value = formatDataPercent(value);
                value = specialMultiply(value);
                value = formatDataFloat(value);
                value = formatTimeData(value);
                value = value.replaceAll("L/min","分每升");
                value = value.replaceAll("ml/h","毫升每时");
                value = value.replaceAll("ml","毫升");
                value = value.replaceAll("mmol/[Ll]","毫摩尔每升");
                value = value.replaceAll("IU","国际单位");
                value = value.replaceAll("mmHg","毫米汞柱");
                value = value.replaceAll("mg/dL","毫克分升");
                value = value.replaceAll("mmHg","毫米汞柱");
                value = value.replaceAll("mmHg","毫米汞柱");
                value = value.replaceAll("mg","毫克");
                value = value.replaceAll("kg","千克");
                value = value.replaceAll("g","克");
                value = value.replaceAll("cm","厘米");
                value = value.replaceAll("㎡ ","平方米");
                value = value.replaceAll("h","小时");
                value = value.replaceAll("/[Ll]","每升");
                value = value.replaceAll("/分","每分");
                value = value.replaceAll("/小时","每小时");
                value = value.replaceAll("/时","每时");
                value = value.replaceAll("/时","每小时");
                value = value.replaceAll("/天","每天");
                value = value.replaceAll("/周","每周");
                value = value.replaceAll("/月","每月");
                value = value.replaceAll("/年","每年");
                value = value.replaceAll("\\+","加");

                //endregion

                /*最终所有数字均为整数*/
                value = formatInt(value);

                //写入Excel中 【这个流只能每次都创建 如果共用流则Excel文件有错误】
                fileOutputStream = new FileOutputStream(targetExcelPath);
                Row targetRow =writeSheet.createRow(i);
                targetRow.createCell(0).setCellValue(value);
                targetFos.write(fileOutputStream);
                if (fileOutputStream != null){
                    fileOutputStream.flush();
                    fileOutputStream.close();
                }
            }
            System.out.println("---------------完成---------------");

        } catch (FileNotFoundException ex) {
            throw new RuntimeException(ex);
        } catch (IOException ex) {
            throw new RuntimeException(ex);
        } finally {
            try {
                if (fileOutputStream != null){
                    fileOutputStream.flush();
                    fileOutputStream.close();
                }
            } catch (IOException e) {
                throw new RuntimeException(e);
            }
            try {
                if (targetFos != null){
                    targetFos.close();
                }
            } catch (IOException e) {
                throw new RuntimeException(e);
            }
            try {
                if (workbook != null){
                    workbook.close();
                }
            } catch (IOException e) {
                throw new RuntimeException(e);
            }
        }

    }

    /**
     * 百分数文本格式化
     * @param value
     * @return
     */
    public String formatDataPercent(String value){
        //value = "0.9%国国国国14:00 国国国国11：53国国国国 L/min国国国国 cm 国国国国mmol/L国国国国  1.5U  国国国国IU 国国国国mmHg 国国国国mg国国国国 kg国国国国 g国国国国 cm 国国国国mg/dL国国国国 ml/h 国国国国㎡   国国国国 /分钟 国国国国 /小时 国国国国 /天 国国国国 /周 国国国国 /月 国国国国 /年  12.98%";
        Pattern pattern = Pattern.compile("[0-9]+[.][0-9]+%");
        Matcher matcher = pattern.matcher(value);
        while (matcher.find()){
            //System.out.println(matcher.group());
            String ele = matcher.group();
            String[] split = ele.substring(0, ele.length() - 1).split("[.]");
            //转换小数点之前的
            Integer i = Integer.valueOf(split[0]);
            String high = numberFormat(i);
            if (high == null){
                return null;
            }
            //转换小数点之后的
            String[] numberString = split[1].split("");
            String smallNumber = simpleConvert(numberString);

            //结果
            String result = high + "点" + smallNumber;
            value = value.replaceAll(ele, result);
        }
        return value;
    }
    /**
     * 浮点数文本格式化
     * @param value
     * @return
     */
    public  String formatDataFloat(String value) {
        //value = "0.9%国国国国14:00 国国国国11：53国国国国 L/min国国国国 cm 国国国国mmol/L国国国国  1.5U  国国国国IU 国国国国mmHg 国国国国mg国国国国 kg国国国国 g国国国国 cm 国国国国mg/dL国国国国 ml/h 国国国国㎡   国国国国 /分钟 国国国国 /小时 国国国国 /天 国国国国 /周 国国国国 /月 国国国国 /年  12.98%";
        Pattern pattern = Pattern.compile("[0-9]+[.][0-9]+");
        Matcher matcher = pattern.matcher(value);
        while (matcher.find()) {
            //System.out.println(matcher.group());
            String ele = matcher.group();
            String[] split = ele.split("[.]");
            //转换小数点之前的
            Integer i = Integer.valueOf(split[0]);
            String high = numberFormat(i);
            if (high == null) {
                return null;
            }
            //转换小数点之后的
            String[] numberString = split[1].split("");
            String smallNumber = simpleConvert(numberString);

            //结果
            String result = high + "点" + smallNumber;
            value = value.replaceAll(ele, result);
        }
        return value;
    }

    /**
     * 科学计数法格式化
     * @param
     * @return
     */
    public  String formatScienceCounting(String value){
        //value = "0.9%国国国国14:00 国国国国11：53国国国国 L/min国国国国 cm 国国国国mmol/L国国国国  1.5U  国国国国IU 国国国国mmHg 国国国国mg国国国国 kg国国国国 g国国国国 cm 国国国国mg/dL国国国国 ml/h 国国国国㎡   国国国国 /分钟 国国国国 /小时 国国国国 /天 国国国国 /周 国国国国 /月 国国国国 /年  12.98% 4.12*10^92";
        Pattern pattern = Pattern.compile("[0-9][.]*[0-9]*[*]10[/^][0-9]+");
        Matcher matcher = pattern.matcher(value);
        String realNum = "";
        String index = "";
        while (matcher.find()){
            //System.out.println(matcher.group());
            String ele = matcher.group();
            //System.out.println(ele);
            String[] split = ele.split("[*]10[/^]");
            //转换真数
            String[] smallNumber = split[0].split("[.]");
            String left = numberFormat(Integer.valueOf(smallNumber[0]));
            if (smallNumber.length >= 2){
                //有小数
                String[] small = smallNumber[1].split("");
                String right = simpleConvert(small);
                realNum = left + "点" + right;
            }else {
                realNum = left;
            }
            //转换指数
            index = numberFormat(Integer.valueOf(split[1]));

            String result = realNum + "乘十的" + index + "次方";
            //正则转换
            String regexTransString = regexTrans(ele);
            value = value.replaceAll(regexTransString, result);
        }
        return value;
    }

    /**
     * 时间文本格式化
     * @param value
     * @return
     */
    public String formatTimeData(String value){
        //value = "0.9%国国国国14:00 国国国国11：53国国国国 L/min国国国国 cm 国国国国mmol/L国国国国  1.5U  国国国国IU 国国国国mmHg 国国国国mg国国国国 kg国国国国 g国国国国 cm 国国国国mg/dL国国国国 ml/h 国国国国㎡   国国国国 /分钟 国国国国 /小时 国国国国 /天 国国国国 /周 国国国国 /月 国国国国 /年  12.98%";
        Pattern pattern = Pattern.compile("[0-9]{1,2}[:：][0-9]{1,2}");
        Matcher matcher = pattern.matcher(value);
        while (matcher.find()){

            String ele = matcher.group();
            String[] split = ele.split("[:：]");
            //转换时间小时
            String hour = numberFormat(Integer.valueOf(split[0]));
            String minute = "";

            //转换分之后的
            if (Integer.valueOf(split[1]) != 00){
                 minute = numberFormat(Integer.valueOf(split[1]));
                String result = hour + "点" + minute;
                value = value.replaceAll(ele, result);
            }else {
                String result = hour + "点" + minute;
                value = value.replaceAll(ele, result);
            }

        }
        return value;
    }

    /**
     * 通用格式化 【】
     * @param value
     * @param regex
     * @param name
     * @return
     *//*
    public String formatCommon(String value, String regex, String name){
        value = "0.9%国国国国14:00 国国国国11：53国国国国 L/min国国国国 cm 国国国国mmol/L国国国国  1.5U  国国国国IU 国国国国mmHg 国国国国mg国国国国 kg国国国国 g国国国国 cm 国国国国mg/dL国国国国 ml/h 国国国国㎡   国国国国 /分钟 国国国国 /小时 国国国国 /天 国国国国 /周 国国国国 /月 国国国国 /年  12.98%";
        Pattern pattern = Pattern.compile(regex);
        Matcher matcher = pattern.matcher(value);
        while (matcher.find()){
            String ele = matcher.group();
            ele.replaceAll(regex,name);
        }
        return value;
    }*/


    /**
     * 简单数字字符串转换
     * @param numberString
     * @return
     */
    public  String simpleConvert(String[] numberString){
        StringBuilder result = new StringBuilder();
        for (String s : numberString) {
            switch (s) {
                case "1" : {result.append("一"); break;}
                case "2" : {result.append("二"); break;}
                case "3" : {result.append("三"); break;}
                case "4" : {result.append("四"); break;}
                case "5" : {result.append("五"); break;}
                case "6" : {result.append("六"); break;}
                case "7" : {result.append("七"); break;}
                case "8" : {result.append("八"); break;}
                case "9" : {result.append("九"); break;}
                case "0" : {result.append("零"); break;}
            }
        }
        return result.toString();
    }



    /**
     * 将含有特殊字符的正则表达式转义
     * @param regex
     */
    public  String regexTrans(String regex){
        String[] fbsArr = { "\\", "$", "(", ")", "*", "+", ".", "[", "]", "?", "^", "{", "}", "|" };
        for (String key : fbsArr) {
            if (regex.contains(key)) {
                regex = regex.replace(key, "\\" + key);
            }
        }
        return regex;
    }

    /**
     * 单独转换 U -- 单位
     * @param value
     */
    public static String  formatU(String value){
         //value = "0.9%国国国国14:00 国国国国11：53国国国国 L/min国国国国 cm 国国国国mmol/L国国国国  1.5U  国国国国IU 国国国国mmHg 国国国国mg国国国国 kg国国国国 g国国国国 cm 国国国国mg/dL国国国国 ml/h 国国国国㎡   国国国国 /分钟 国国国国 /小时 国国国国 /天 国国国国 /周 国国国国 /月 国国国国 /年  12.98%";
        Pattern pattern = Pattern.compile("[0-9]U");
        Matcher matcher = pattern.matcher(value);
        while (matcher.find()){
            String ele = matcher.group();
            //System.out.println(ele);
            String[] split = ele.split("");

            value = value.replaceAll(ele, split[0] + "单位");
        }
       return value;
    }

    /**
     * 格式化整数
     * @param value
     * @return
     */
    public String  formatInt(String value){
        //String value = "1234 1234 12341234 12 2 17835024427 012 测试测试";
        //负向后行零宽断言 + 负向先行零宽断言
        Pattern pattern = Pattern.compile("(?<!\\d)[1-9][0-9]{0,6}(?!\\d)");
        Matcher matcher = pattern.matcher(value);
        while (matcher.find()){
            String ele = matcher.group();
            //format numValue -- numString
            String numString = numberFormat(Integer.valueOf(ele));
            //获取下标
            String regex = "(?<!\\d)" + ele + "(?!\\d)";
            value = value.replaceAll(regex, numString);
        }
        return value;
    }

    /**
     * 针对 {1.1 X|x 1} {1.1 X|x 1.1} {1 X|x 1.1} {1 X|x 1}格式的转换
     * @param value
     * @return
     */
    public  String specialMultiply(String value){
        //value = "  遵医嘱给予0.9%氯化钠注射液50ml静脉冲管,  患者左脚踝破溃1.1X0.5cm，泡沫敷料保护左脚踝皮肤，尿道口渗出淡红色尿液，阴囊呈轻度水肿，嘱其用干毛巾托起阴囊。0.511  1x1 1X3.2";
        Pattern pattern = Pattern.compile("[0-9]+[.]*[0-9]*[Xx][0-9]+[.]*[0-9]*");
        Matcher matcher = pattern.matcher(value);
        String a = "";
        String b = "";
        while (matcher.find()){
            //System.out.println(matcher.group());
            String ele = matcher.group();
            String[] split = ele.split("[Xx]");
            //转换乘数a
            String[] aArray = split[0].split("[.]");
            String a_left = numberFormat(Integer.valueOf(aArray[0]));
            if (aArray.length >= 2){
                //有小数
                String[] small = aArray[1].split("");
                String a_right = simpleConvert(small);
                a = a_left + "点" + a_right;
            }else {
                a = a_left;
            }
            //转换乘数b
            String[] bArray = split[1].split("[.]");
            String b_left = numberFormat(Integer.valueOf(bArray[0]));
            if (bArray.length >= 2){
                //有小数
                String[] small = bArray[1].split("");
                String b_right = simpleConvert(small);
                b = b_left + "点" + b_right;
            }else {
                b = b_left;
            }

            String result = a + "乘" + b;

            //正则转换
            String regexTransString = regexTrans(ele);
            value = value.replaceAll(regexTransString, result);
        }

        return value;
    }

}
